# This test exercises behavior of foreign keys in the face of concurrent
# detach of partitions in the referenced table.
# (The cases where the detaching transaction is cancelled is interesting
# because the locking situation is completely different.  I didn't verify
# that keeping both variants adds any extra coverage.)
#
# Note: Always keep "s2noop" right after "s1cancel" in permutations.  This
# reduces the probability of the timing problem that the cancel error report
# is shown together with the next query instead of with the cancel query.

setup {
	drop table if exists d4_primary, d4_primary1, d4_fk, d4_pid;
	create table d4_primary (a int primary key) partition by list (a);
	create table d4_primary1 partition of d4_primary for values in (1);
	create table d4_primary2 partition of d4_primary for values in (2);
	insert into d4_primary values (1);
	insert into d4_primary values (2);
	create table d4_fk (a int references d4_primary);
	insert into d4_fk values (2);
	create table d4_pid (pid int);
}

session "s1"
step "s1b"			{ begin; }
step "s1brr"		{ begin isolation level repeatable read; }
step "s1s"			{ select * from d4_primary; }
# Sleep 0.1s after sending cancel, to give s2 time to react
step "s1cancel" 	{ select pg_cancel_backend(pid), pg_sleep(0.1) from d4_pid; }
step "s1insert"		{ insert into d4_fk values (1); }
step "s1c"			{ commit; }
step "s1declare"	{ declare f cursor for select * from d4_primary; }
step "s1declare2"	{ declare f cursor for select * from d4_fk where a = 2; }
step "s1fetchall"	{ fetch all from f; }
step "s1fetchone"	{ fetch 1 from f; }
step "s1updcur"		{ update d4_fk set a = 1 where current of f; }
step "s1svpt"		{ savepoint f; }
step "s1rollback"	{ rollback to f; }

session "s2"
step "s2snitch" { insert into d4_pid select pg_backend_pid(); }
step "s2detach" { alter table d4_primary detach partition d4_primary1 concurrently; }
step "s2noop"	{ UNLISTEN noop; }

session "s3"
step "s3brr"		{ begin isolation level repeatable read; }
step "s3insert"		{ insert into d4_fk values (1); }
step "s3commit"		{ commit; }
step "s3vacfreeze"	{ vacuum freeze pg_catalog.pg_inherits; }

# Trying to insert into a partially detached partition is rejected
permutation "s2snitch" "s1b"   "s1s" "s2detach" "s1cancel" "s2noop" "s1insert" "s1c"
permutation "s2snitch" "s1b"   "s1s" "s2detach"            "s1insert" "s1c"
# ... even under REPEATABLE READ mode.
permutation "s2snitch" "s1brr" "s1s" "s2detach" "s1cancel" "s2noop" "s1insert" "s1c"
permutation "s2snitch" "s1brr" "s1s" "s2detach"            "s1insert" "s1c"

# If you read the referenced table using a cursor, you can see a row that the
# RI query does not see.
permutation "s2snitch" "s1b" "s1declare" "s2detach" "s1cancel" "s2noop" "s1fetchall" "s1insert" "s1c"
permutation "s2snitch" "s1b" "s1declare" "s2detach"            "s1fetchall" "s1insert" "s1c"
permutation "s2snitch" "s1b" "s1declare" "s2detach" "s1cancel" "s2noop" "s1svpt" "s1insert" "s1rollback" "s1fetchall" "s1c"
permutation "s2snitch" "s1b" "s1declare" "s2detach"            "s1svpt" "s1insert" "s1rollback" "s1fetchall" "s1c"
permutation "s2snitch" "s1b" "s2detach" "s1declare" "s1cancel" "s2noop" "s1fetchall" "s1insert" "s1c"
permutation "s2snitch" "s1b" "s2detach" "s1declare"            "s1fetchall" "s1insert" "s1c"
permutation "s2snitch" "s1b" "s2detach" "s1declare" "s1cancel" "s2noop" "s1svpt" "s1insert" "s1rollback" "s1fetchall" "s1c"
permutation "s2snitch" "s1b" "s2detach" "s1declare"            "s1svpt" "s1insert" "s1rollback" "s1fetchall" "s1c"

# Creating the referencing row using a cursor
permutation "s2snitch" "s1brr" "s1declare2" "s1fetchone" "s2detach" "s1cancel" "s2noop" "s1updcur" "s1c"
permutation "s2snitch" "s1brr" "s1declare2" "s1fetchone" "s2detach"            "s1updcur" "s1c"
permutation "s2snitch" "s1brr" "s1declare2" "s1fetchone" "s1updcur" "s2detach" "s1c"

# Try reading the table from an independent session.
permutation "s2snitch" "s1b" "s1s" "s2detach" "s3insert" "s1c"
permutation "s2snitch" "s1b" "s1s" "s2detach" "s3brr" "s3insert" "s3commit" "s1cancel" "s2noop" "s1c"
permutation "s2snitch" "s1b" "s1s" "s2detach" "s3brr" "s3insert" "s3commit" "s1c"

# Try one where we VACUUM FREEZE pg_inherits (to verify that xmin change is
# handled correctly).
permutation "s2snitch" "s1brr" "s1s" "s2detach" "s1cancel" "s2noop" "s3vacfreeze" "s1s" "s1insert" "s1c"
permutation "s2snitch" "s1b" "s1s" "s2detach" "s1cancel" "s2noop" "s3vacfreeze" "s1s" "s1insert" "s1c"
